#ifndef __LWIP_H__
#define __LWIP_H__

#include <global/header/types.h>

typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned long u32_t;
typedef signed long s32_t;

#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define ENOTBLK 15
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define ETXTBSY 26
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define ERANGE 34
#define EDEADLK 35
#define ENAMETOOLONG 36
#define ENOLCK 37
#define ENOSYS 38
#define ENOTEMPTY 39
#define ELOOP 40
#define EWOULDBLOCK EAGAIN
#define ENOMSG 42
#define EIDRM 43
#define ECHRNG 44
#define EL2NSYNC 45
#define EL3HLT 46
#define EL3RST 47
#define ELNRNG 48
#define EUNATCH 49
#define ENOCSI 50
#define EL2HLT 51
#define EBADE 52
#define EBADR 53
#define EXFULL 54
#define ENOANO 55
#define EBADRQC 56
#define EBADSLT 57
#define EDEADLOCK EDEADLK
#define EBFONT 59
#define ENOSTR 60
#define ENODATA 61
#define ETIME 62
#define ENOSR 63
#define ENONET 64
#define ENOPKG 65
#define EREMOTE 66
#define ENOLINK 67
#define EADV 68
#define ESRMNT 69
#define ECOMM 70
#define EPROTO 71
#define EMULTIHOP 72
#define EDOTDOT 73
#define EBADMSG 74
#define EOVERFLOW 75
#define ENOTUNIQ 76
#define EBADFD 77
#define EREMCHG 78
#define ELIBACC 79
#define ELIBBAD 80
#define ELIBSCN 81
#define ELIBMAX 82
#define ELIBEXEC 83
#define EILSEQ 84
#define ERESTART 85
#define ESTRPIPE 86
#define EUSERS 87
#define ENOTSOCK 88
#define EDESTADDRREQ 89
#define EMSGSIZE 90
#define EPROTOTYPE 91
#define ENOPROTOOPT 92
#define EPROTONOSUPPORT 93
#define ESOCKTNOSUPPORT 94
#define EOPNOTSUPP 95
#define EPFNOSUPPORT 96
#define EAFNOSUPPORT 97
#define EADDRINUSE 98
#define EADDRNOTAVAIL 99
#define ENETDOWN 100
#define ENETUNREACH 101
#define ENETRESET 102
#define ECONNABORTED 103
#define ECONNRESET 104
#define ENOBUFS 105
#define EISCONN 106
#define ENOTCONN 107
#define ESHUTDOWN 108
#define ETOOMANYREFS 109
#define ETIMEDOUT 110
#define ECONNREFUSED 111
#define EHOSTDOWN 112
#define EHOSTUNREACH 113
#define EALREADY 114
#define EINPROGRESS 115
#define ESTALE 116
#define EUCLEAN 117
#define ENOTNAM 118
#define ENAVAIL 119
#define EISNAM 120
#define EREMOTEIO 121
#define EDQUOT 122
#define ENOMEDIUM 123
#define EMEDIUMTYPE 124
#define ENSROK 0
#define ENSRNODATA 160
#define ENSRFORMERR 161
#define ENSRSERVFAIL 162
#define ENSRNOTFOUND 163
#define ENSRNOTIMP 164
#define ENSRREFUSED 165
#define ENSRBADQUERY 166
#define ENSRBADNAME 167
#define ENSRBADFAMILY 168
#define ENSRBADRESP 169
#define ENSRCONNREFUSED 170
#define ENSRTIMEOUT 171
#define ENSROF 172
#define ENSRFILE 173
#define ENSRNOMEM 174
#define ENSRDESTRUCTION 175
#define ENSRQUERYDOMAINTOOLONG 176
#define ENSRCNAMELOOP 177

extern int errno;

struct in_addr {
  u32_t s_addr;
};

#define INADDR_NONE ((u32_t)0xffffffffUL)
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL)
#define INADDR_ANY ((u32_t)0x00000000UL)
#define INADDR_BROADCAST ((u32_t)0xffffffffUL)

u32_t inet_addr(const char *cp);
int   inet_aton(const char *cp, struct in_addr *addr);
char *inet_ntoa(struct in_addr addr);

u16_t htons(u16_t x);
u16_t ntohs(u16_t x);
u32_t htonl(u32_t x);
u32_t ntohl(u32_t x);

struct ip_addr {
  u32_t addr;
} __attribute__((packed));

struct ip_addr2 {
  u16_t addrw[2];
} __attribute__((packed));

struct netif;

extern const struct ip_addr ip_addr_any;
extern const struct ip_addr ip_addr_broadcast;

#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
#define IN_CLASSA_NET 0xff000000
#define IN_CLASSA_NSHIFT 24
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
#define IN_CLASSA_MAX 128
#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IN_CLASSB_NET 0xffff0000
#define IN_CLASSB_NSHIFT 16
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
#define IN_CLASSB_MAX 65536
#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IN_CLASSC_NET 0xffffff00
#define IN_CLASSC_NSHIFT 8
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IN_CLASSD_NET 0xf0000000
#define IN_CLASSD_NSHIFT 28
#define IN_CLASSD_HOST 0x0fffffff
#define IN_MULTICAST(a) IN_CLASSD(a)
#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IN_LOOPBACKNET 127
#define IP4_ADDR(ipaddr,a,b,c,d) (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | ((u32_t)((b) & 0xff) << 16) | ((u32_t)((c) & 0xff) << 8) | (u32_t)((d) & 0xff))
#define ip_addr_set(dest,src) (dest)->addr = ((src) == NULL? 0: (src)->addr)
#define ip_addr_netcmp(addr1,addr2,mask) (((addr1)->addr & (mask)->addr) == ((addr2)->addr & (mask)->addr))
#define ip_addr_cmp(addr1,addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))
#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)
#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)
#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
#define ip_ntoa(addr) ((addr != NULL) ? inet_ntoa(*((struct in_addr*)(addr))) : "NULL")

struct sockaddr_in {
  u8_t sin_len;
  u8_t sin_family;
  u16_t sin_port;
  struct in_addr sin_addr;
  char sin_zero[8];
};

struct sockaddr {
  u8_t sa_len;
  u8_t sa_family;
  char sa_data[14];
};

#define socklen_t u32_t
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define SO_DEBUG 0x0001
#define SO_ACCEPTCONN 0x0002
#define SO_REUSEADDR 0x0004
#define SO_KEEPALIVE 0x0008
#define SO_DONTROUTE 0x0010
#define SO_BROADCAST 0x0020
#define SO_USELOOPBACK 0x0040
#define SO_LINGER 0x0080
#define SO_OOBINLINE 0x0100
#define SO_REUSEPORT 0x0200
#define SO_DONTLINGER ((int)(~SO_LINGER))
#define SO_SNDBUF 0x1001
#define SO_RCVBUF 0x1002
#define SO_SNDLOWAT 0x1003
#define SO_RCVLOWAT 0x1004
#define SO_SNDTIMEO 0x1005
#define SO_RCVTIMEO 0x1006
#define SO_ERROR 0x1007
#define SO_TYPE 0x1008
#define SO_CONTIMEO 0x1009
#define SO_NO_CHECK 0x100a

struct linger {
       int l_onoff;
       int l_linger;
};

#define SOL_SOCKET 0xfff
#define AF_UNSPEC 0
#define AF_INET 2
#define PF_INET AF_INET
#define PF_UNSPEC AF_UNSPEC
#define IPPROTO_IP 0
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define IPPROTO_UDPLITE 136
#define MSG_PEEK 0x01
#define MSG_WAITALL 0x02
#define MSG_OOB 0x04
#define MSG_DONTWAIT 0x08
#define MSG_MORE 0x10
#define IP_TOS 1
#define IP_TTL 2
#define TCP_NODELAY 0x01
#define TCP_KEEPALIVE 0x02
#define TCP_KEEPIDLE 0x03
#define TCP_KEEPINTVL 0x04
#define TCP_KEEPCNT 0x05
#define IPTOS_TOS_MASK 0x1E
#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
#define IPTOS_LOWCOST 0x02
#define IPTOS_MINCOST IPTOS_LOWCOST
#define IPTOS_PREC_MASK 0xe0
#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK)
#define IPTOS_PREC_NETCONTROL 0xe0
#define IPTOS_PREC_INTERNETCONTROL 0xc0
#define IPTOS_PREC_CRITIC_ECP 0xa0
#define IPTOS_PREC_FLASHOVERRIDE 0x80
#define IPTOS_PREC_FLASH 0x60
#define IPTOS_PREC_IMMEDIATE 0x40
#define IPTOS_PREC_PRIORITY 0x20
#define IPTOS_PREC_ROUTINE 0x00
#define IOCPARM_MASK 0x7fU
#define IOC_VOID 0x20000000UL
#define IOC_OUT 0x40000000UL
#define IOC_IN 0x80000000UL
#define IOC_INOUT (IOC_IN|IOC_OUT)
#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#define FIONREAD _IOR('f', 127, unsigned long)
#define FIONBIO _IOW('f', 126, unsigned long)
#define SIOCSHIWAT _IOW('s', 0, unsigned long)
#define SIOCGHIWAT _IOR('s', 1, unsigned long)
#define SIOCSLOWAT _IOW('s', 2, unsigned long)
#define SIOCGLOWAT _IOR('s', 3, unsigned long)
#define SIOCATMARK _IOR('s', 7, unsigned long)
#define O_NONBLOCK 04000U

struct timeval {
	 long tv_sec;
	 long tv_usec;
};

/* #undef  FD_SETSIZE */
/* /\* Make FD_SETSIZE match NUM_SOCKETS in socket.c *\/ */
/* #define FD_SETSIZE    MEMP_NUM_NETCONN */
/* #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7))) */
/* #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) */
/* #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7))) */
/* #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p))) */

/* typedef struct fd_set { */
/* 	 unsigned char fd_bits [(FD_SETSIZE+7)/8]; */
/* } fd_set; */

u16_t lwip_htons(u16_t x);
u16_t lwip_ntohs(u16_t x);
u32_t lwip_htonl(u32_t x);
u32_t lwip_ntohl(u32_t x);

/* BSD SOCKET API */
/* select api are excluded by the ugly style */

int lwip_accept(int s, struct sockaddr *addr, u32_t *addrlen);
int lwip_bind(int s, const struct sockaddr *name, u32_t namelen);
int lwip_shutdown(int s, int how);
int lwip_getpeername (int s, struct sockaddr *name, u32_t *namelen);
int lwip_getsockname (int s, struct sockaddr *name, u32_t *namelen);
int lwip_getsockopt (int s, int level, int optname, void *optval, u32_t *optlen);
int lwip_setsockopt (int s, int level, int optname, const void *optval, u32_t optlen);
int lwip_close(int s);
int lwip_connect(int s, const struct sockaddr *name, u32_t namelen);
int lwip_listen(int s, int backlog);
int lwip_recv(int s, void *mem, size_t len, int flags);
int lwip_read(int s, void *mem, size_t len);
int lwip_recvfrom(int s, void *mem, size_t len, int flags,
      struct sockaddr *from, u32_t *fromlen);
int lwip_send(int s, const void *dataptr, size_t size, int flags);
int lwip_sendto(int s, const void *dataptr, size_t size, int flags,
    const struct sockaddr *to, u32_t tolen);
int lwip_socket(int domain, int type, int protocol);
int lwip_write(int s, const void *dataptr, size_t size);
int lwip_ioctl(int s, long cmd, void *argp);
/* int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, */
/*                 struct timeval *timeout); */

#endif
